<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="rRRVy" id="rRRVy"><span data-lake-id="u2b4394f5" id="u2b4394f5">典型回答</span></h1>
  <p data-lake-id="uabafb8bd" id="uabafb8bd"><br></p>
  <p data-lake-id="u2ac5056a" id="u2ac5056a"><span data-lake-id="u10c90f40" id="u10c90f40">很多时候，我们的数据库表中会存储很多敏感信息，如用户的手机号、身份证号、密码之类的，这些数据如果不做好加密的话，一旦数据泄漏就会导致重要信息泄露。</span></p>
  <p data-lake-id="ueecd2a7a" id="ueecd2a7a"><span data-lake-id="u678bc309" id="u678bc309">​</span><br></p>
  <p data-lake-id="u06abd2b5" id="u06abd2b5"><span data-lake-id="u9c8fd35c" id="u9c8fd35c">一般来说都需要对敏感字段进行加密，然后再在数据库中保存加密后的数据，这样即使被拖库也没关系，比如攻击者拿到的只是加密后的密码，并不知道真实密码是什么。</span></p>
  <p data-lake-id="u57358a66" id="u57358a66"><span data-lake-id="ufe3effe8" id="ufe3effe8">​</span><br></p>
  <p data-lake-id="ud90655d6" id="ud90655d6"><br></p>
  <p data-lake-id="u8e47816c" id="u8e47816c"><span data-lake-id="uefcc9839" id="uefcc9839">那么，我们应该如何做数据库的加密呢。通常来说有以下几种办法：</span></p>
  <p data-lake-id="u7d95267a" id="u7d95267a"><span data-lake-id="u595c7ee7" id="u595c7ee7">​</span><br></p>
  <h3 data-lake-id="cXyfd" id="cXyfd"><span data-lake-id="u9e6cbb13" id="u9e6cbb13">服务端加解密</span></h3>
  <p data-lake-id="u071967d6" id="u071967d6"><br></p>
  <p data-lake-id="ufaffb8bd" id="ufaffb8bd"><span data-lake-id="u0240ea58" id="u0240ea58">服务端加解密指的就是数据库在存入数据库之前就加密好，然后再从数据库取出之后进行解密。这样可以保证数据库的数据绝对安全，因为数据库也不知道明文到底是什么。</span></p>
  <p data-lake-id="u34db1f14" id="u34db1f14"><span data-lake-id="ub7a7ec02" id="ub7a7ec02">​</span><br></p>
  <p data-lake-id="u54a15ffa" id="u54a15ffa"><span data-lake-id="u0684fc16" id="u0684fc16">一般来说我们可以选择各种各样的加密算法，如对称加密和非对称加密都可以，一般来说用对称加密就行了。</span></p>
  <p data-lake-id="u485b6e31" id="u485b6e31"><span data-lake-id="u57a25dc6" id="u57a25dc6">​</span><br></p>
  <p data-lake-id="ube472697" id="ube472697"><br></p>
  <p data-lake-id="uf2c4b154" id="uf2c4b154"><span data-lake-id="ueb14d589" id="ueb14d589">当然，有些场景下也可以用MD5（MD5严格来说并不是加密算法，只是一种hash算法），但是需要注意的是MD5不支持解密，所以只能用于那种存储后只做匹配而不作查询展示的场景，如用户的密码。而需要展示的场景，如手机号等就需要支持解密。</span></p>
  <p data-lake-id="u10657a86" id="u10657a86"><br></p>
  <h3 data-lake-id="QDGKj" id="QDGKj"><span data-lake-id="u7189cf9b" id="u7189cf9b">数据库加密函数</span></h3>
  <p data-lake-id="u79768276" id="u79768276"><br></p>
  <p data-lake-id="u42ab1951" id="u42ab1951"><span data-lake-id="u73490d57" id="u73490d57">MySQL提供了一些内置的加密函数，我们可以直接使用这些加密函数进行数据加密：</span></p>
  <p data-lake-id="uec012e3c" id="uec012e3c"><span data-lake-id="uba37c39b" id="uba37c39b">​</span><br></p>
  <ol list="ua1f77aa7">
   <li fid="u2fb9a1a5" data-lake-id="ua1a2e316" id="ua1a2e316"><span data-lake-id="u178b4454" id="u178b4454">AES_ENCRYPT 和 AES_DECRYPT，这两个函数是对称加密算法，使用对称密钥加密，这意味着加密和解密都使用相同的密钥。因此，必须确保密钥的安全性。</span></li>
  </ol>
  <ul list="u67c69282" data-lake-indent="1">
   <li fid="uf595d709" data-lake-id="u7e25a529" id="u7e25a529"><span data-lake-id="ub734b21e" id="ub734b21e">AES_ENCRYPT(str, key) 用于使用AES算法对字符串 str 进行加密，key表示使用的密钥。</span></li>
   <li fid="uf595d709" data-lake-id="ub3f8caf4" id="ub3f8caf4"><span data-lake-id="u50671c79" id="u50671c79">AES_DECRYPT(crypt_str, key) 用于解密已加密的字符串 crypt_str，使用相同的密钥 key。</span></li>
  </ul>
  <p data-lake-id="ua5da405a" id="ua5da405a"><span data-lake-id="u367815a4" id="u367815a4">​</span><br></p>
  <pre lang="java"><code>
-- 加密数据
INSERT INTO user_data (username, credit_card) VALUES ('Hollis', AES_ENCRYPT('1234-5678-9012-3456', 'hollis_secret_key'));

-- 解密数据
SELECT username, AES_DECRYPT(credit_card, 'hollis_secret_key') FROM user_data WHERE username = 'John';
</code></pre>
  <p data-lake-id="ueede2182" id="ueede2182"><span data-lake-id="u3beed929" id="u3beed929">​</span><br></p>
  <ol list="ua1f77aa7" start="2">
   <li fid="u2fb9a1a5" data-lake-id="u25362c53" id="u25362c53"><span data-lake-id="u51e259db" id="u51e259db">ENCRYPT</span><span data-lake-id="u58f20fd6" id="u58f20fd6">： </span><span data-lake-id="u7b535410" id="u7b535410">ENCRYPT(str, salt)</span><span data-lake-id="u2923c2ce" id="u2923c2ce"> 函数使用UNIX crypt()函数对字符串 </span><span data-lake-id="u996fb6d1" id="u996fb6d1">str</span><span data-lake-id="u689cc12d" id="u689cc12d"> 进行加密，其中 </span><span data-lake-id="u21f41fe3" id="u21f41fe3">salt</span><span data-lake-id="u1a25a8c0" id="u1a25a8c0"> 是一个2字符的随机盐。这种加密方法通常用于密码存储，但不是最安全的加密方式。</span></li>
  </ol>
  <p data-lake-id="ue664364d" id="ue664364d"><span data-lake-id="ue3f78890" id="ue3f78890">​</span><br></p>
  <pre lang="java"><code>
-- 使用随机盐加密密码
INSERT INTO user_credentials (username, password_hash) VALUES ('Hollis', ENCRYPT('my_password', 'ab'));

-- 验证密码
SELECT * FROM user_credentials WHERE username = 'Hollis' AND password_hash = ENCRYPT('entered_password', password_hash);
</code></pre>
  <ol list="ua1f77aa7" start="3">
   <li fid="u2fb9a1a5" data-lake-id="u93860d3f" id="u93860d3f"><span data-lake-id="u3bf018da" id="u3bf018da">MD5</span><span data-lake-id="u5573b800" id="u5573b800"> 和 </span><span data-lake-id="u55e2f194" id="u55e2f194">SHA1</span><span data-lake-id="ue5b363a3" id="ue5b363a3">：</span></li>
  </ol>
  <ul list="u81018327" data-lake-indent="1">
   <li fid="u35b94475" data-lake-id="uad72d2b8" id="uad72d2b8"><span data-lake-id="u11c039d2" id="u11c039d2">MD5(str)</span><span data-lake-id="u9f2ff479" id="u9f2ff479"> 和 </span><span data-lake-id="u42ff5f0a" id="u42ff5f0a">SHA1(str)</span><span data-lake-id="u82346f5d" id="u82346f5d"> 函数分别用于计算字符串 </span><span data-lake-id="ub0175c4d" id="ub0175c4d">str</span><span data-lake-id="u5ed3719f" id="u5ed3719f"> 的MD5和SHA-1哈希值。这不是真正的加密，而是散列函数，无法逆向解密。</span></li>
  </ul>
  <p data-lake-id="ueaecf87e" id="ueaecf87e"><span data-lake-id="u168282c3" id="u168282c3">​</span><br></p>
  <pre lang="java"><code>
-- 存储MD5哈希值
INSERT INTO user_data (username, password_hash) VALUES ('Hollis', MD5('hollis666'));

-- 验证密码
SELECT * FROM user_data WHERE username = 'Hollis' AND password_hash = MD5('hollis666');
</code></pre>
  <p data-lake-id="u591bab50" id="u591bab50"><br></p>
  <ol list="ua1f77aa7" start="4">
   <li fid="u2fb9a1a5" data-lake-id="u0a9378dd" id="u0a9378dd"><span data-lake-id="u0c22477a" id="u0c22477a">PASSWORD</span><span data-lake-id="ubb0e1fb6" id="ubb0e1fb6">： </span><span data-lake-id="uf3962762" id="uf3962762">PASSWORD(str)</span><span data-lake-id="u21978f30" id="u21978f30"> 函数将字符串 </span><span data-lake-id="u26f3eb84" id="u26f3eb84">str</span><span data-lake-id="ua20ffd07" id="ua20ffd07"> 加密为MySQL原生密码散列。这通常用于MySQL用户密码的存储。</span></li>
  </ol>
  <p data-lake-id="uf137c52b" id="uf137c52b"><span data-lake-id="u4ac79d2c" id="u4ac79d2c">​</span><br></p>
  <pre lang="java"><code>
-- 存储MySQL原生密码散列
INSERT INTO mysql_users (username, password_hash) VALUES ('Hollis', PASSWORD('hollis666'));
</code></pre>
  <p data-lake-id="u7e5b7585" id="u7e5b7585"><span data-lake-id="ufe7c8a9f" id="ufe7c8a9f">​</span><br></p>
  <ol list="ua1f77aa7" start="5">
   <li fid="u2fb9a1a5" data-lake-id="u9aeab68a" id="u9aeab68a"><span data-lake-id="ue43c7d49" id="ue43c7d49">DES_ENCRYPT 和 DES_DECRYPT，需要注意：DES算法不够安全，通常不建议使用：</span></li>
  </ol>
  <ul list="ua4b4fc73" data-lake-indent="1">
   <li fid="ue2c3fc56" data-lake-id="ufec1b974" id="ufec1b974"><span data-lake-id="u04a311c4" id="u04a311c4">DES_ENCRYPT(str, key_str)</span><span data-lake-id="ue1bd01a2" id="ue1bd01a2"> 用于使用DES算法对字符串 </span><span data-lake-id="u46dbd652" id="u46dbd652">str</span><span data-lake-id="ued2aae5f" id="ued2aae5f"> 进行加密，使用提供的密钥字符串 </span><span data-lake-id="u97feaefb" id="u97feaefb">key_str</span><span data-lake-id="u4136f8b3" id="u4136f8b3">。</span></li>
   <li fid="ue2c3fc56" data-lake-id="udce4ffa4" id="udce4ffa4"><span data-lake-id="u7a83ad55" id="u7a83ad55">DES_DECRYPT(crypt_str, key_str)</span><span data-lake-id="u050949ad" id="u050949ad"> 用于解密已加密的字符串 </span><span data-lake-id="u8405d22f" id="u8405d22f">crypt_str</span><span data-lake-id="u6f5c7766" id="u6f5c7766">，使用相同的密钥字符串 </span><span data-lake-id="u4fe60771" id="u4fe60771">key_str</span><span data-lake-id="ua814f25e" id="ua814f25e">。</span></li>
  </ul>
  <p data-lake-id="uf332b5c4" id="uf332b5c4"><br></p>
  <h3 data-lake-id="J8GoF" id="J8GoF"><span data-lake-id="uf7fad2c1" id="uf7fad2c1">InnoDB静态加密</span></h3>
  <p data-lake-id="u96e3dcd0" id="u96e3dcd0"><br></p>
  <p data-lake-id="u8d8333e0" id="u8d8333e0"><span data-lake-id="uafd6cb1a" id="uafd6cb1a">MySQL 5.7开始，InnoDB支持对静态数据加密。适用于按表的文件表空间、常规表空间、mysql系统表空间、redolog和undolog进行加密。</span></p>
  <p data-lake-id="u67ebc478" id="u67ebc478"><span data-lake-id="u4fcaf1b4" id="u4fcaf1b4">​</span><br></p>
  <p data-lake-id="u5cd1ab28" id="u5cd1ab28"><span data-lake-id="u6dd52227" id="u6dd52227">从MySQL 8.0.16开始，还支持为schema和常规表空间设置默认加密，这允许DBA控制是否对在这些schema和表空间中创建的表进行加密。</span></p>
  <p data-lake-id="ua44c8454" id="ua44c8454"><span data-lake-id="u9a4e3cec" id="u9a4e3cec">​</span><br></p>
  <p data-lake-id="u62cca6ce" id="u62cca6ce"><span data-lake-id="u892dde04" id="u892dde04">关于表空间的加密，大家可以下官方文档中有比较详细的描述，这种加密一般都是DBA负责的：</span></p>
  <p data-lake-id="ue67ac1a1" id="ue67ac1a1"><span data-lake-id="u7ad7f13b" id="u7ad7f13b">​</span><br></p>
  <p data-lake-id="u97fb2b8f" id="u97fb2b8f"><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-data-encryption.html#innodb-schema-tablespace-encryption-default" target="_blank" data-lake-id="u7f19438a" id="u7f19438a"><span data-lake-id="u221f5a57" id="u221f5a57">https://dev.mysql.com/doc/refman/8.0/en/innodb-data-encryption.html#innodb-schema-tablespace-encryption-default</span></a></p>
  <p data-lake-id="ubb1f6f3d" id="ubb1f6f3d"><span data-lake-id="u9165d64e" id="u9165d64e">​</span><br></p>
  <h3 data-lake-id="A2cqO" id="A2cqO"><span data-lake-id="u1ca21dd0" id="u1ca21dd0">使用加密数据库</span></h3>
  <p data-lake-id="uc6fb0767" id="uc6fb0767"><br></p>
  <p data-lake-id="u2ae016b1" id="u2ae016b1"><span data-lake-id="u6970ae95" id="u6970ae95">除了以上几个方案，使用加密库是一种常见的方法，以下是一些常用的加密库，它们提供了各种加密算法和功能，以帮助你保护数据的安全性：</span></p>
  <p data-lake-id="u26ee1503" id="u26ee1503"><span data-lake-id="ue3c84fe5" id="ue3c84fe5">​</span><br></p>
  <ol list="u6152b96b">
   <li fid="uabfd189d" data-lake-id="uc7d83fa5" id="uc7d83fa5"><span data-lake-id="u5227d156" id="u5227d156">OpenSSL</span><span data-lake-id="u5fbf2c64" id="u5fbf2c64">：OpenSSL是一个功能强大的开源加密库，提供了许多加密算法和协议的实现，包括SSL/TLS、AES、DES、RSA等。它广泛用于网络通信和数据加密。</span></li>
   <li fid="uabfd189d" data-lake-id="u5b8d5626" id="u5b8d5626"><span data-lake-id="ubf43f6d3" id="ubf43f6d3">Libsodium</span><span data-lake-id="u9e2aba24" id="u9e2aba24">：Libsodium是一个现代的、易于使用的加密库，提供高级加密功能，如公钥加密、数字签名和安全哈希。它的API设计旨在降低开发者在正确使用加密时的复杂性。</span></li>
   <li fid="uabfd189d" data-lake-id="u222a2653" id="u222a2653"><span data-lake-id="u155105a5" id="u155105a5">Bouncy Castle：Bouncy Castle是一个Java加密库，提供了丰富的密码和加密算法的实现，包括公钥基础设施、数字签名和对称密钥加密。</span></li>
   <li fid="uabfd189d" data-lake-id="u5022fc04" id="u5022fc04"><span data-lake-id="ucc87888d" id="ucc87888d">Crypto++</span><span data-lake-id="u32a9cc68" id="u32a9cc68">：Crypto++是一个C++加密库，提供了广泛的密码和加密算法的实现，包括DES、AES、RSA、SHA等。它在C++项目中非常受欢迎。</span></li>
   <li fid="uabfd189d" data-lake-id="u9dd0f33b" id="u9dd0f33b"><span data-lake-id="u1172051f" id="u1172051f">Google Tink：Google Tink是Google开发的加密库，它专注于简化安全编程，并提供了一组现代密码库，用于密码学原语的安全实现，如AES、HMAC、Digital Signatures等。</span></li>
   <li fid="uabfd189d" data-lake-id="u36c6ec9b" id="u36c6ec9b"><span data-lake-id="uc23b4931" id="uc23b4931">PyCryptodome：PyCryptodome是Python的加密库，提供了各种密码和加密算法的实现，包括AES、DES、RSA、SHA等。它是Python中广泛使用的加密库。</span></li>
  </ol>
  <p data-lake-id="uf10fac28" id="uf10fac28"><span data-lake-id="u9ae48feb" id="u9ae48feb">​</span><br></p>
  <p data-lake-id="u8b6f8db1" id="u8b6f8db1"><span data-lake-id="udc856dce" id="udc856dce">​</span><br></p>
  <h1 data-lake-id="auuF1" id="auuF1"><span data-lake-id="ub1c59e45" id="ub1c59e45">扩展知识</span></h1>
  <p data-lake-id="u6e4909a0" id="u6e4909a0"><br></p>
  <h2 data-lake-id="UP1fi" id="UP1fi"><span data-lake-id="u17416bff" id="u17416bff">加密后会带来哪些问题</span></h2>
  <p data-lake-id="u254fb1bb" id="u254fb1bb"><br></p>
  <p data-lake-id="u08efeda4" id="u08efeda4"><span data-lake-id="ueb5bbb07" id="ueb5bbb07">加密可以保证数据的安全，但是对数据进行加密也并不是全无缺点的，一般来说存在以下几个缺点：</span></p>
  <p data-lake-id="u7034643f" id="u7034643f"><span data-lake-id="uf2de2902" id="uf2de2902">​</span><br></p>
  <ul list="u863b2f0e">
   <li fid="u52704e4b" data-lake-id="u6d7c8b23" id="u6d7c8b23" data-lake-index-type="true"><span data-lake-id="ua08b92ea" id="ua08b92ea">性能开销：加密和解密数据会引入额外的计算开销，这可能导致数据库性能下降。加密操作通常需要更多的CPU资源，因此在高负载环境中，可能需要更强大的硬件来维持性能水平。</span></li>
   <li fid="u52704e4b" data-lake-id="u6d958bfd" id="u6d958bfd" data-lake-index-type="true"><span data-lake-id="uba13fee0" id="uba13fee0">复杂性：加密引入了复杂性，包括密钥管理、加密算法的选择和配置等。不正确的配置和管理可能导致数据泄露或安全漏洞。</span></li>
   <li fid="u52704e4b" data-lake-id="u21e8af85" id="u21e8af85" data-lake-index-type="true"><span data-lake-id="u79e5a06b" id="u79e5a06b">查询和检索困难：加密数据的查询和检索通常更加困难，</span><strong><span data-lake-id="u4075661d" id="u4075661d">尤其是在进行模糊查询或部分匹配时</span></strong><span data-lake-id="ub3070eb2" id="ub3070eb2">。需要采用额外的技术来解决这些问题。</span></li>
   <li fid="u52704e4b" data-lake-id="u627b95a8" id="u627b95a8" data-lake-index-type="true"><span data-lake-id="u0e7b0a4a" id="u0e7b0a4a">密钥管理：密钥管理是关键的问题。如果加密密钥不受良好的保护，那么整个安全性可能会受到威胁。密钥管理要求严格的访问控制和监控，以防止未经授权的访问。如果你丢失了加密密钥，那么加密数据将无法解密，这可能导致数据永久不可用。</span></li>
  </ul>
  <p data-lake-id="ue9e5f1a7" id="ue9e5f1a7"><span data-lake-id="uab054b9e" id="uab054b9e">​</span><br></p>
  <p data-lake-id="ue4ecf762" id="ue4ecf762"><span data-lake-id="ua8cb5c37" id="ua8cb5c37">​</span><br></p>
 </body>
</html>